home *** CD-ROM | disk | FTP | other *** search
- // ===========================================================================
- // CDocSpeech.cp C++ source code for speech recognition facilities
- // ===========================================================================
-
- #include "CDocSpeech.h"
-
- extern Boolean gHasSpeechRecog;
-
- //global variables
- SRRecognitionSystem gSystem;
- SRRecognizer gRecognizer;
- SRLanguageModel gGApplLM;
- SRLanguageModel gGDocuLM;
- SRPhrase gRevert;
- CDocSpeech *gDocSpeechObj = nil; //the single instance of this class
-
- //function prototypes
- void SetLanguageObjectState (SRLanguageObject inObj, Boolean isEnabled);
-
- OSErr MyNewLanguageModel(ResIDT stringResource, short stringId, SRLanguageModel *theModel);
- OSErr MyNewPhrase(ResIDT stringResource, short stringId, SRPhrase *thePhrase);
- OSErr MyAddText(SRLanguageModel theModel, ResIDT stringResource, short stringId, long refCon);
-
- // ===========================================================================
- // • CDocSpeech Class
- // ===========================================================================
- // ---------------------------------------------------------------------------
- // • CDocSpeech
- // ---------------------------------------------------------------------------
- // Constructor
- // Initialize speech recognition for this application.
-
- CDocSpeech::CDocSpeech()
- {
- OSErr theErr = noErr;
-
- //open a recognition system
- if (!theErr) {
- theErr = ::SROpenRecognitionSystem(&gSystem, kSRDefaultRecognitionSystemID);
- }
-
- //set recognition system properties
- //we want the user-selected feedback and listening modes
- if (!theErr) {
- short theModes = kSRHasFeedbackHasListenModes;
- theErr = ::SRSetProperty(gSystem, kSRFeedbackAndListeningModes, &theModes, sizeof(theModes));
- }
-
- //create a recognizer with default speech source
- if (!theErr)
- theErr = ::SRNewRecognizer(gSystem, &gRecognizer, kSRDefaultSpeechSource);
-
- //set recognizer properties
- //we want to receive notifications when recognition begins and ends
- if (!theErr) {
- unsigned long theParam = kSRNotifyRecognitionBeginning | kSRNotifyRecognitionDone;
- theErr = ::SRSetProperty(gRecognizer, kSRNotificationParam, &theParam, sizeof(theParam));
- }
-
- //install AppleEvent handlers
- if (!theErr) {
- theErr = ::AEInstallEventHandler(kAESpeechSuite, kAESpeechDetected, NewAEEventHandlerProc(HandleSpeechBegunAppleEvent), 0, false);
- theErr = ::AEInstallEventHandler(kAESpeechSuite, kAESpeechDone, NewAEEventHandlerProc(HandleSpeechDoneAppleEvent), 0, false);
- }
-
- //make our language models
- if (!theErr)
- theErr = MakeLanguageModels();
-
- //install initial language model and release our reference to it
- if (!theErr) {
- theErr = ::SRSetLanguageModel(gRecognizer, gGApplLM);
- ::SRReleaseObject(gGApplLM);
- }
-
- //have the recognizer start processing sound
- if (!theErr)
- theErr = ::SRStartListening(gRecognizer);
-
- }
-
- // ---------------------------------------------------------------------------
- // • ~CDocSpeech
- // ---------------------------------------------------------------------------
- // Destructor
-
- CDocSpeech::~CDocSpeech()
- {
- ::SRStopListening(gRecognizer);
- ::SRReleaseObject(gRecognizer);
- ::SRReleaseObject(gGDocuLM);
- ::SRReleaseObject(gRevert);
- ::SRCloseRecognitionSystem(gSystem);
- }
-
- // ---------------------------------------------------------------------------
- // • MakeLanguageModels
- // ---------------------------------------------------------------------------
- // Create the language models.
- // We create one top-level language model, <gApplLM>.
- // All other LMs are embedded language models.
- //
- // Here is a BNF version of the models we want to create:
- //
- // <Menu Commands> = <Universal Commands> | <Document Commands>
- //
- // <Universal Commands> = <Universal Commands> | About DocDemo;
- // <UFileLM> = New | Open | Page Setup | Quit;
- // <Document Commands> = <Document File Commands> | <Document Edit Commands>;
- // <Document File Commands> = Close | Save | Save As | Revert | Print | Print One;
- // <Document Edit Commands> = Undo | Cut | ... | Clear | Select All;
- //
-
- OSErr
- CDocSpeech::MakeLanguageModels (void)
- {
- OSErr theErr = noErr;
- SRLanguageModel myGUnivLM; // embedded language models
- SRLanguageModel myUFileLM;
- SRLanguageModel myDFileLM;
- SRLanguageModel myDEditLM;
-
- //make the language models [which are initially empty]
- // The error handling is a bit repetitive, but necessary
- if(!theErr)
- theErr = MyNewLanguageModel(rSTR_LMNames, kStr_GApplLM, &gGApplLM);
- if(!theErr)
- theErr = MyNewLanguageModel(rSTR_LMNames, kStr_GUnivLM, &myGUnivLM);
- if(!theErr)
- theErr = MyNewLanguageModel(rSTR_LMNames, kStr_UFileLM, &myUFileLM);
- if(!theErr)
- theErr = MyNewLanguageModel(rSTR_LMNames, kStr_GDocuLM, &gGDocuLM);
- if(!theErr)
- theErr = MyNewLanguageModel(rSTR_LMNames, kStr_DFileLM, &myDFileLM);
- if(!theErr)
- theErr = MyNewLanguageModel(rSTR_LMNames, kStr_DEditLM, &myDEditLM);
-
- //make any other language objects we'll need
- if(!theErr)
- theErr = MyNewPhrase(kSTR_DFileCmds, kStr_Revert, &gRevert);
-
-
- //****<Universal File Commands>****
- if(!theErr)
- theErr = MyAddText(myUFileLM, kSTR_UFileCmds, kStr_New, cmd_New);
- if(!theErr)
- theErr = MyAddText(myUFileLM, kSTR_UFileCmds, kStr_Open, cmd_Open);
- if(!theErr)
- theErr = MyAddText(myUFileLM, kSTR_UFileCmds, kStr_PageSetup, cmd_PageSetup);
- if(!theErr)
- theErr = MyAddText(myUFileLM, kSTR_UFileCmds, kStr_Quit, cmd_Quit);
- //****<Universal File Commands>****
-
- //****<Document File Commands>****
- if(!theErr)
- theErr = MyAddText(myDFileLM, kSTR_DFileCmds, kStr_Close, cmd_Close);
- if(!theErr)
- theErr = MyAddText(myDFileLM, kSTR_DFileCmds, kStr_Save, cmd_Save);
- if(!theErr)
- theErr = MyAddText(myDFileLM, kSTR_DFileCmds, kStr_SaveAs, cmd_SaveAs);
-
- unsigned long theRefCon = cmd_Revert;
- if(!theErr)
- theErr = ::SRSetProperty(gRevert, kSRRefCon, &theRefCon, sizeof(theRefCon));
- if(!theErr)
- theErr = ::SRAddLanguageObject(myDFileLM, gRevert);
-
- if(!theErr)
- theErr = MyAddText(myDFileLM, kSTR_DFileCmds, kStr_Print, cmd_Print);
- if(!theErr)
- theErr = MyAddText(myDFileLM, kSTR_DFileCmds, kStr_PrintOne, cmd_PrintOne);
- //****<Document File Commands>****
-
- //****<Document Edit Commands>****
- if(!theErr)
- theErr = MyAddText(myDEditLM, kSTR_DEditCmds, kStr_Undo, cmd_Undo);
- if(!theErr)
- theErr = MyAddText(myDEditLM, kSTR_DEditCmds, kStr_Cut, cmd_Cut);
- if(!theErr)
- theErr = MyAddText(myDEditLM, kSTR_DEditCmds, kStr_Copy, cmd_Copy);
- if(!theErr)
- theErr = MyAddText(myDEditLM, kSTR_DEditCmds, kStr_Paste, cmd_Paste);
- if(!theErr)
- theErr = MyAddText(myDEditLM, kSTR_DEditCmds, kStr_Clear, cmd_Clear);
- if(!theErr)
- theErr = MyAddText(myDEditLM, kSTR_DEditCmds, kStr_SelectAll, cmd_SelectAll);
- //****<Document Edit Commands>****
-
- //****<Document Commands>****
- if(!theErr)
- theErr = ::SRAddLanguageObject(gGDocuLM, myDFileLM);
- if(!theErr)
- theErr = ::SRAddLanguageObject(gGDocuLM, myDEditLM);
- //****<Document Commands>****
-
- //****<Universal Commands>****
- if(!theErr)
- theErr = ::SRAddLanguageObject(myGUnivLM, myUFileLM);
- if(!theErr)
- MyAddText(myGUnivLM, kSTR_UApplCmds, kStr_About, cmd_About);
- //****<Universal Commands>****
-
- // ****<Menu Commands>****
- if(!theErr)
- theErr = ::SRAddLanguageObject(gGApplLM, myGUnivLM);
- if(!theErr)
- theErr = ::SRAddLanguageObject(gGApplLM, gGDocuLM);
- //****<Menu Commands>****
-
- // release any embedded language models we don’t need later
- if(!theErr)
- {
- ::SRReleaseObject(myDFileLM);
- ::SRReleaseObject(myUFileLM);
- ::SRReleaseObject(myGUnivLM);
- }
-
- return theErr;
-
- }
-
- // ---------------------------------------------------------------------------
- // • HandleSpeechBegunAppleEvent
- // ---------------------------------------------------------------------------
- // Handle recognition begun Apple event.
-
- pascal OSErr
- CDocSpeech::HandleSpeechBegunAppleEvent (AppleEvent *theAEevt, AppleEvent* reply, long refcon)
- {
- #pragma unused(reply, refcon)
-
- long actualSize;
- DescType actualType;
- OSErr theErr = noErr, recStatus = noErr;
- SRRecognizer theRec;
- LWindow *theWindow;
-
- //get status and recognizer
- theErr = ::AEGetParamPtr(theAEevt, keySRSpeechStatus, typeShortInteger, &actualType, (Ptr)&recStatus, sizeof(recStatus), &actualSize);
-
- if (!theErr && !recStatus)
- theErr = ::AEGetParamPtr(theAEevt, keySRRecognizer, typeSRRecognizer, &actualType, (Ptr)&theRec, sizeof(theRec), &actualSize);
-
- if(theErr)
- if(!theRec) return theErr;
-
- //figure out what state we're in, then enable the appropriate language model
- theWindow = UDesktop::FetchTopRegular(); //look for a document window
-
- if (theWindow != nil) { //there is a document window open
- //theErr = ::SRSetLanguageModel(gRecognizer, gGApplLM);
- SetLanguageObjectState(gGDocuLM, kEnableObj);
-
- //make sure to turn off "Revert" if there's no file or it isn't dirty
- //[notice the clever way we determine if Revert shoud be enabled!]
- Boolean isEnabled;
- Boolean outUsesMark;
- Char16 outMark;
- Str255 outName;
-
- LCommander::GetTarget()->FindCommandStatus(cmd_Revert, isEnabled, outUsesMark, outMark, outName);
- if (isEnabled)
- SetLanguageObjectState(gRevert, kEnableObj);
- else
- SetLanguageObjectState(gRevert, kDisableObj);
-
- // Similar gyrations with the edit menu should be done here
-
- } else { //there is no document window open
- //theErr = ::SRSetLanguageModel(gRecognizer, gGApplLM);
- SetLanguageObjectState(gGDocuLM, kDisableObj);
- }
-
- //now tell the recognizer to continue
- theErr = ::SRContinueRecognition(theRec);
- return theErr;
- }
-
- // ---------------------------------------------------------------------------
- // • HandleSpeechDoneAppleEvent
- // ---------------------------------------------------------------------------
- // Handle speech done Apple event.
- // Here's our strategy: all commands are one item, which carries
- // a unique refCon value. We extract the refCon and then pass it as a command to
- // the current target.
-
- pascal OSErr
- CDocSpeech::HandleSpeechDoneAppleEvent (AppleEvent *theAEevt, AppleEvent* reply, long refcon)
- {
- #pragma unused(reply, refcon)
-
- long actualSize;
- DescType actualType;
- OSErr theErr = 0, recStatus = 0;
- SRRecognitionResult recResult = nil;
- Size theLen;
- SRPath thePath;
- SRSpeechObject theItem;
- long theRefCon; //refcon of item
-
- //get status
- theErr = ::AEGetParamPtr(theAEevt, keySRSpeechStatus, typeShortInteger, &actualType, (Ptr)&recStatus, sizeof(theErr), &actualSize);
-
- //get result
- if (!theErr && !recStatus)
- theErr = ::AEGetParamPtr(theAEevt, keySRSpeechResult, typeSRSpeechResult, &actualType, (Ptr)&recResult, sizeof(SRRecognitionResult), &actualSize);
-
- //get command from result by reading the refcon of the relevant object
- if (!theErr && !recStatus) {
- ::SRGetProperty(recResult, kSRPathFormat, &thePath, &theLen);
- theErr = ::SRGetIndexedItem(thePath, &theItem, 0);
- if (!theErr) {
- theLen = sizeof(theRefCon);
- ::SRGetProperty(theItem, kSRRefCon, &theRefCon, &theLen);
- ::SRReleaseObject(theItem);
- }
- //release recognition result, since we're done with it
- ::SRReleaseObject(recResult);
- ::SRReleaseObject(thePath);
- }
-
- LCommander::GetTarget()->ObeyCommand((MessageT)theRefCon, nil);
-
- return theErr;
- }
-
- // ---------------------------------------------------------------------------
- // • SetLanguageObjectState
- // ---------------------------------------------------------------------------
- // Enable or disable a language object.
-
- void SetLanguageObjectState (SRLanguageObject inObj, Boolean isEnabled)
- {
- Boolean theState = isEnabled;
-
- ::SRSetProperty(inObj, kSREnabled, &theState, sizeof(theState));
- }
-
-
- // These next few routines were added to make error handling a little cleaner
- // in MakeLanguageModels
-
- // ---------------------------------------------------------------------------
- // • MyNewLanguageModel
- // ---------------------------------------------------------------------------
- // Make a new language model named with the given string.
-
- OSErr MyNewLanguageModel(ResIDT stringResource, short stringId, SRLanguageModel *theModel)
- {
- Str255 theStr;
- OSErr theErr;
-
- ::GetIndString(theStr, stringResource, stringId);
- if(theStr[0] == 0)
- theErr = -1; // Signal error if empty string
- else
- theErr = ::SRNewLanguageModel(gSystem, theModel, &theStr[1], theStr[0]);
-
- return theErr;
- }
-
- // ---------------------------------------------------------------------------
- // • MyNewPhrase
- // ---------------------------------------------------------------------------
- // Make a new phrase with the given string.
-
- OSErr MyNewPhrase(ResIDT stringResource, short stringId, SRPhrase *thePhrase)
- {
- Str255 theStr;
- OSErr theErr;
-
- ::GetIndString(theStr, stringResource, stringId);
- if(theStr[0] == 0)
- theErr = -1; // Signal error if empty string
- else
- theErr = ::SRNewPhrase(gSystem, thePhrase, &theStr[1], theStr[0]);
-
- return theErr;
- }
-
- // ---------------------------------------------------------------------------
- // • MyAddText
- // ---------------------------------------------------------------------------
- // Add the given string to the given language model with the given refcon.
-
- OSErr MyAddText(SRLanguageModel theModel, ResIDT stringResource, short stringId, long refCon)
- {
- Str255 theStr;
- OSErr theErr;
-
- ::GetIndString(theStr, stringResource, stringId);
- if(theStr[0] == 0)
- theErr = -1; // Signal error if empty string
- else
- theErr = ::SRAddText(theModel, &theStr[1], theStr[0], refCon);
-
- return theErr;
- }
-